home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************************
-
- Gnucleus - A node application for the Gnutella network
- Copyright (C) 2000 John Marshall
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- For support, questions, comments, etc...
- E-Mail:
- swabby@c0re.net
-
- Address:
- 21 Cadogan Way
- Nashua, NH, USA 03062
-
- ********************************************************************************/
-
- #include "stdafx.h"
- #include "HeaderCtrlEx.h"
-
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- #include "Resource.h"
-
- /////////////////////////////////////////////////////////////////////////////
- // CMyHeaderCtrl
-
- CMyHeaderCtrl::CMyHeaderCtrl() : marker_rect(0,0,0,0)
- {
- m_pWidth = NULL;
- m_bDragging = FALSE;
- m_bCheckForDrag = FALSE;
- m_fpDragCol = NULL;
- m_pOwnerWnd = NULL;
-
- // Default to being unsorted.
- m_bSortAsc = FALSE;
- m_nSortCol = -1;
- }
-
- CMyHeaderCtrl::CMyHeaderCtrl(CWnd *pWnd, void (CWnd::*fpDragCol)(int, int))
- : marker_rect(0,0,0,0)
- {
- m_pWidth = NULL;
- m_bDragging = FALSE;
- m_bCheckForDrag = FALSE;
- m_fpDragCol = fpDragCol;
- m_pOwnerWnd = pWnd;
- }
-
- CMyHeaderCtrl::~CMyHeaderCtrl()
- {
- }
-
-
- BEGIN_MESSAGE_MAP(CMyHeaderCtrl, CHeaderCtrl)
- //{{AFX_MSG_MAP(CMyHeaderCtrl)
- ON_WM_MOUSEMOVE()
- ON_WM_LBUTTONUP()
- ON_WM_LBUTTONDOWN()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CMyHeaderCtrl message handlers
-
- void CMyHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point)
- {
- if( (MK_LBUTTON & nFlags) == 0)
- {
- // The left mouse button is not pressed - so reset flags
- m_bCheckForDrag = FALSE;
- m_bDragging = FALSE;
- }
- else if( m_bDragging )
- {
- // Get column number that falls under the mouse
- int i=0, cx = 0;
- if( point.x > 0 )
- for( i = 0; i < GetItemCount(); i++ )
- {
- if( point.x >= cx && point.x < cx + m_pWidth[i] )
- break;
- cx += m_pWidth[i];
- }
-
- if( i != m_nDropPos )
- {
- m_nDropPos = i;
-
- CRect rect;
- GetWindowRect( &rect );
-
- // Invalidate area occupied by previous marker
- InvalidateRect( &marker_rect );
-
- // Draw a new marker
- CClientDC dc(this);
- POINT pts[3];
- pts[0].x = cx; pts[1].x = cx -3; pts[2].x = cx +3;
- pts[0].y = rect.Height(); pts[1].y = pts[2].y = rect.Height() -7;
- dc.Polygon( pts, 3 );
-
- // save marker information
- marker_rect.left = cx - 4;
- marker_rect.top = rect.Height() -8;
- marker_rect.right = cx + 4;
- marker_rect.bottom = rect.Height();
- }
- return;
- }
- else if( m_bCheckForDrag )
- {
- // The mouse button was pressed over a column header
- // and now the mouse has moved - so start drag
- m_bCheckForDrag = FALSE;
-
- m_bDragging = TRUE;
- m_nDropPos = m_nDragCol;
-
- SetCapture();
-
- // Store information for later use
- int iCount = GetItemCount();
- HD_ITEM hd_item;
- m_pWidth = new int[iCount];
- for( int i = 0; i < iCount; i++ )
- {
- hd_item.mask = HDI_WIDTH;
- GetItem( i, &hd_item );
- m_pWidth[i] = hd_item.cxy;
-
- }
- return;
- }
-
- CHeaderCtrl::OnMouseMove(nFlags, point);
- }
-
- /**
- * Finish a column drag if one was started.
- */
- void CMyHeaderCtrl::OnLButtonUp(UINT nFlags, CPoint point)
- {
- ASSERT( m_pOwnerWnd != NULL && m_fpDragCol != NULL );
-
- if( m_bDragging )
- {
- m_bDragging = FALSE;
- delete[] m_pWidth;
- ReleaseCapture();
- Invalidate();
-
- // Call the callback function.
- if( m_nDragCol != m_nDropPos && m_nDragCol != m_nDropPos -1 )
- {
- (m_pOwnerWnd->*m_fpDragCol)( m_nDragCol, m_nDropPos );
-
- // If the currently sorted column is the one being dragged
- // Mark it as being sorted in its dropped position
- if ( m_nSortCol == m_nDragCol )
- SetSortImage( m_nDropPos, m_bSortAsc );
- }
- }
- CHeaderCtrl::OnLButtonUp(nFlags, point);
- }
-
-
- /**
- * Setup a callback for the dragging of a column
- *
- */
- void CMyHeaderCtrl::SetCallback( CWnd* pWnd, void (CWnd::*fpDragCol)(int, int) )
- {
- m_fpDragCol = fpDragCol;
- m_pOwnerWnd = pWnd;
- }
-
- /**
- * See if a drag is starting over one of the columns.
- */
- void CMyHeaderCtrl::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // Determine if mouse was pressed over a column header
- HD_HITTESTINFO hd_hittestinfo;
- hd_hittestinfo.pt = point;
- SendMessage(HDM_HITTEST, 0, (LPARAM)(&hd_hittestinfo));
- if( hd_hittestinfo.flags == HHT_ONHEADER )
- {
- m_nDragCol = hd_hittestinfo.iItem;
- m_bCheckForDrag = TRUE;
- }
-
- CHeaderCtrl::OnLButtonDown(nFlags, point);
- }
-
- /**
- * Set the type of image to display in this column.
- * (Either ascending, or descending)
- */
- int CMyHeaderCtrl::SetSortImage( int nCol, BOOL bAsc )
- {
- m_nSortCol = nCol;
- m_bSortAsc = bAsc;
-
- // Change the item to ownder drawn
- HD_ITEM hditem;
-
- hditem.mask = HDI_FORMAT;
- GetItem( nCol, &hditem );
- hditem.fmt |= HDF_OWNERDRAW;
- SetItem( nCol, &hditem );
-
- // Invalidate header control so that it gets redrawn
- Invalidate();
-
- return 1;
- }
-
-
- void CMyHeaderCtrl::RemoveSortImage( int iItem )
- {
- if( iItem != -1 )
- {
- HD_ITEM hditem;
- hditem.mask = HDI_FORMAT;
- GetItem( iItem, &hditem );
- hditem.mask = HDI_FORMAT;
- hditem.fmt &= ~HDF_BITMAP;
- SetItem( iItem, &hditem );
- }
- }
-
- void CMyHeaderCtrl::RemoveAllSortImages()
- {
- int iCount = GetItemCount();
- for( int i = 0; i < iCount; i++ )
- RemoveSortImage( i );
- }
-
-
-
- void CMyHeaderCtrl::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
- {
- CDC dc;
-
- dc.Attach( lpDrawItemStruct->hDC );
-
- // Get the column rect
- CRect rcLabel( lpDrawItemStruct->rcItem );
-
- // Save DC
- int nSavedDC = dc.SaveDC();
-
- // Set clipping region to limit drawing within column
- CRgn rgn;
- rgn.CreateRectRgnIndirect( &rcLabel );
- dc.SelectObject( &rgn );
- rgn.DeleteObject();
-
- #pragma warning( push , 3)
- // Draw the background
- dc.FillRect(rcLabel, &CBrush(::GetSysColor(COLOR_3DFACE)));
- #pragma warning( pop )
-
- // Labels are offset by a certain amount
- // This offset is related to the width of a space character
- int offset = dc.GetTextExtent(_T(" "), 1 ).cx*2;
-
-
- // Get the column text and format
- TCHAR buf[256];
- HD_ITEM hditem;
-
- hditem.mask = HDI_TEXT | HDI_FORMAT;
- hditem.pszText = buf;
- hditem.cchTextMax = 255;
-
- GetItem( lpDrawItemStruct->itemID, &hditem );
-
- // Determine format for drawing column label
- UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP
- | DT_VCENTER | DT_END_ELLIPSIS ;
-
- if( hditem.fmt & HDF_CENTER)
- uFormat |= DT_CENTER;
- else if( hditem.fmt & HDF_RIGHT)
- uFormat |= DT_RIGHT;
- else
- uFormat |= DT_LEFT;
-
- // Adjust the rect if the mouse button is pressed on it
- if( lpDrawItemStruct->itemState == ODS_SELECTED )
- {
- rcLabel.left++;
- rcLabel.top += 2;
- rcLabel.right++;
- }
-
- // Adjust the rect further if Sort arrow is to be displayed
- if( lpDrawItemStruct->itemID == (UINT)m_nSortCol )
- {
- rcLabel.right -= 3 * offset;
- }
-
- rcLabel.left += offset;
- rcLabel.right -= offset;
-
- // Draw column label
- if( rcLabel.left < rcLabel.right )
- dc.DrawText(buf,-1,rcLabel, uFormat);
-
- // Draw the Sort arrow
- if( lpDrawItemStruct->itemID == (UINT)m_nSortCol )
- {
- CRect rcIcon( lpDrawItemStruct->rcItem );
-
- // Set up pens to use for drawing the triangle
- CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
- CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
- CPen *pOldPen = dc.SelectObject( &penLight );
-
- if( m_bSortAsc )
- {
- // Draw triangle pointing upwards
- dc.MoveTo( rcIcon.right - 2*offset, offset-1);
- dc.LineTo( rcIcon.right - 3*offset/2, rcIcon.bottom - offset );
- dc.LineTo( rcIcon.right - 5*offset/2-2, rcIcon.bottom - offset );
- dc.MoveTo( rcIcon.right - 5*offset/2-1, rcIcon.bottom - offset-1 );
-
- dc.SelectObject( &penShadow );
- dc.LineTo( rcIcon.right - 2*offset, offset-2);
- }
- else
- {
- // Draw triangle pointing downwords
- dc.MoveTo( rcIcon.right - 3*offset/2, offset-1);
- dc.LineTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset + 1 );
- dc.MoveTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset );
-
- dc.SelectObject( &penShadow );
- dc.LineTo( rcIcon.right - 5*offset/2-1, offset -1 );
- dc.LineTo( rcIcon.right - 3*offset/2, offset -1);
- }
-
- // Restore the pen
- dc.SelectObject( pOldPen );
- }
-
- // Restore dc
- dc.RestoreDC( nSavedDC );
-
- // Detach the dc before returning
- dc.Detach();
- }